package socket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 服务端
 */
public class Server {
    /*
        运行在服务端的ServerSocket主要有2个工作:
        1.申请服务端口8088,客户端通过该端口与服务端建立连接;
        2.监听该端口8088,一旦一个客户端请求连接,则连接成功,返回一个Socket;
          使用该Socket就可以实现与客户端交互了;
     */
    private ServerSocket serverSocket;
    // 使用线程安全的集合来保存所有客户端连接
    private CopyOnWriteArrayList<ClientHandler> clients = new CopyOnWriteArrayList<>();
    //线程池
    private ExecutorService pool;

    public Server() {
        try {
            System.out.println("正在启动服务端...");
            serverSocket = new ServerSocket(8088); //范围是0-65535,尽量使用6000以后的端口号;
            pool = Executors.newFixedThreadPool(20);
            System.out.println("服务端启动成功");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start() {
        try {
            while (true) {
                //阻塞函数,如果没有客户端过来连接,会一直阻塞,直到有客户端过来连接,连接成功后返回一个Socket
                System.out.println("等待客户端连接...");
                Socket socket = serverSocket.accept();
                System.out.println("有一个客户端连接了!!!");

                // 创建客户端处理器并添加到客户端列表
                ClientHandler handler = new ClientHandler(socket);
                clients.add(handler);

                //利用多线程处理客户端请求
                //Thread t = new Thread(handler);
                //t.start();
                //提交任务到线程池
                pool.execute(handler);

                System.out.println("当前在线客户端数量: " + clients.size());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 广播消息给所有客户端
    private void broadcast(String message, ClientHandler sender) {
        if (clients.isEmpty()) {
            return;
        }

        // 遍历所有客户端并发送消息
        for (ClientHandler client : clients) {
            // 不发送给消息的发送者（可选，根据需求决定）
            if (client != sender && client.isConnected()) {
                try {
                    client.sendMessage(message);
                } catch (IOException e) {
                    System.out.println("向客户端发送消息失败: " + e.getMessage());
                    // 发送失败可能意味着客户端已断开，将其从列表中移除
                    removeClient(client);
                }
            }
        }
    }

    // 移除客户端
    private void removeClient(ClientHandler client) {
        clients.remove(client);
        System.out.println("客户端断开连接，当前在线客户端数量: " + clients.size());
    }

    public static void main(String[] args) {
        Server server = new Server();
        server.start();
    }

    // 定义一个成员内部类,可以访问外部类的所有资源;
    // 定义一个线程任务,该线程任务负责与一个指定的客户端交互;
    private class ClientHandler implements Runnable {
        private Socket socket;
        private OutputStream out;
        private String clientInfo;

        public ClientHandler(Socket socket) {
            this.socket = socket;
            this.clientInfo = socket.getInetAddress().getHostAddress() + ":" + socket.getPort();
        }

        public void run() {
            try {
                // 获取输出流，用于向客户端发送数据
                out = socket.getOutputStream();

                InputStream in = socket.getInputStream();
                byte[] buffer = new byte[1024];
                int len;

                // 发送欢迎消息
                sendMessage("欢迎来到聊天室！当前在线人数: " + clients.size());
                // 广播新用户加入消息
                broadcast("系统: 用户 " + clientInfo + " 加入了聊天室", this);

                while ((len = in.read(buffer)) != -1) {
                    String message = new String(buffer, 0, len, StandardCharsets.UTF_8).trim();

                    if (!message.isEmpty()) {
                        String formattedMessage = clientInfo + ": " + message;
                        System.out.println("收到消息: " + formattedMessage);

                        // 广播消息给所有客户端
                        broadcast(formattedMessage, this);
                    }
                }
            } catch (IOException e) {
                System.out.println("客户端 " + clientInfo + " 连接异常: " + e.getMessage());
            } finally {
                // 客户端断开连接时的清理工作
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                removeClient(this);
                // 广播用户离开消息
                broadcast("系统: 用户 " + clientInfo + " 离开了聊天室", this);
            }
        }

        // 向客户端发送消息
        public void sendMessage(String message) throws IOException {
            if (out != null && !socket.isClosed()) {
                out.write(message.getBytes(StandardCharsets.UTF_8));
                out.flush();
            }
        }

        // 检查客户端是否还连接
        public boolean isConnected() {
            return socket != null && !socket.isClosed() && socket.isConnected();
        }

        public String getClientInfo() {
            return clientInfo;
        }
    }
}